interface Button {
  btntype: string
  text: string
}
interface Link {
  alt: string
  href: string
}
interface Href {
  linktype: string
  target: Openlocation
}
enum Openlocation {
  self = 0,
  _blank,
  parent,
}
let button: Button = {
  btntype: 'normal',
  text: '跳转到百度',
}
let link: Link = {
  alt: 'goto baidu',
  href: 'http://www.baidu.com',
}
let href: Href = {
  linktype: '外网',
  target: Openlocation._blank,
}

/**
 * 参数 是类的对象 || 对象  || 是type的对象 || 接口的对象
 */
// 泛型函数重载+交叉类型+泛型约束
/**
 */
function cross<T extends object, U extends object>(objOne: T, objTwo: U): T & U
function cross<T extends object, U extends object, V extends object>(
  objOne: T,
  objTwo: U,
  objThree: V
): T & U & V

function cross<T extends object, U extends object, V extends object>(
  objOne: T,
  objTwo: U,
  objThree?: V
) {
  /** 这里为什么要空对象，因为其他对象类型无法保证传过来的是一致的而且能够类型断言
   *  因为要把空对象断言成交叉类型之后才可以把值放空对象里面 所以要定义空对象类型
   */
  let obj = {}
  let combine = obj as T & U // 断言成 T 和 U  只允许添加 T 或 U 的属性 空对象可以像任何对象断言
  Object.keys(objOne).forEach((key) => {
    combine[key] = objOne[key]
  })
  Object.keys(objTwo).forEach((key) => {
    if (!obj.hasOwnProperty(key)) {
      combine[key] = objTwo[key]
    }
  })
  if (objThree) {
    //如果有第三个对象传递进来实现交叉
    //let obj = {}
    //let combine2 = obj as T & U & V
    //let combine2=combine as T & U & V
    // 为什么 typeof combine 也可以呢？ 因为获取的是Combine的类型 鼠标放过去还是 let combine: T & U
    let combine2 = combine as typeof combine & V
    Object.keys(objThree).forEach((key) => {
      if (!combine2.hasOwnProperty(key)) {
        combine2[key] = objThree[key]
      }
    })
    return combine2
  }
  return combine
}

let combine = cross(button, link, href)
// let combine2 = cross(combine, href)
console.log(combine)
// console.log(combine2)

export {}
